package component

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"gitee.com/crack007/goose/helper"
	"github.com/crack007/go-im/src/common/model"
	"strings"
	"time"
)

var ErrExpired = errors.New("token过期")
var ErrValid = errors.New("token格式错误")
var ErrSign = errors.New("签名错误")

type jwt struct {
	key string
}

func NewJwt(key string) *jwt {
	return &jwt{
		key: key,
	}
}
func (j *jwt) GenerateToken(PayLoad *model.JwtPayloadModel) (string, error) {
	payloadString, err := json.Marshal(PayLoad)
	if err != nil {
		return "", err
	}
	jwtModel := model.JwtModel{}
	jwtModel.Header.Alg = "md5"
	jwtModel.Header.Type = "jwt"
	jwtModel.PayLoad = PayLoad
	jwtModel.Signature = j.sign(string(payloadString))
	header, err := json.Marshal(jwtModel.Header)
	if err != nil {
		return "", err
	}
	jwtHeader := base64.StdEncoding.EncodeToString(header)
	jwtPayload := base64.StdEncoding.EncodeToString(payloadString)
	jwtSign := base64.StdEncoding.EncodeToString([]byte(jwtModel.Signature))
	return jwtHeader + "." + jwtPayload + "." + jwtSign, nil
}

func (j *jwt) Parse(data string) (*model.JwtPayloadModel, error) {
	jwtList := strings.Split(data, ".")
	if len(jwtList) != 3 {
		return nil, ErrValid
	}

	payloadString, err := base64.StdEncoding.DecodeString(jwtList[1])
	if err != nil {
		return nil, ErrValid
	}
	// 过期校验
	jwtPayload := &model.JwtPayloadModel{}
	err = json.Unmarshal(payloadString, jwtPayload)
	if err != nil {
		return nil, ErrValid
	}
	expAt := jwtPayload.Iat + jwtPayload.Exp
	if uint32(time.Now().Unix()) > expAt {
		return nil, ErrExpired
	}
	// 签名校验
	sign, err := base64.StdEncoding.DecodeString(jwtList[2])
	if err != nil {
		return nil, err
	}
	if string(sign) != j.sign(string(payloadString)) {
		return nil, ErrSign
	}
	return jwtPayload, nil
}

func (j *jwt) sign(data string) string {
	return helper.Md5(data + "sign=" + j.key)
}
